﻿/**
 * 远光ECP平台3.0版本 http://www.ygsoft.com/ Grace [Gris Application Cloud-Computing
 * Extension]
 * 
 * 对百度上传控件封装
 * 
 * 变更版本：
 * zhengxianwei@ygsoft.com 2016-05-13 创建
 */
define(["jquery", "ecp.utils", "webuploader"],function($, utils, $webUploader){
	/**
	 * 默认参数.
	 */
	var defaultOptions = {
		//指定选择文件的按钮容器，不指定则不创建按钮
		pick: {
			//指定按钮文字。不指定时优先从指定的容器中看是否自带文字。
		    innerHTML: "添加附件...",
		    //是否开起同时选择多个文件能力
		    multiple:true 
		},
		//指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。
//		accept: {  
//			//文字描述
//			title: 'Images',  
//			//允许的文件后缀，不带点，多个用逗号分割。
//			extensions: 'gif,jpg,jpeg,bmp,png,pdf,txt,doc,docx,xls,xlsx,ppt,pptx,pub,XSM,rar,zip',
//			//多个用逗号分割。
//			mimeTypes: 'file/*'
//		},
		//指定Drag And Drop拖拽的容器，如果不指定，则不启动
		dnd: '',
		//是否禁掉整个页面的拖拽功能，如果不禁用，图片拖进来的时候会默认被浏览器打开。
//		disableGlobalDnd: false,
		//指定监听paste事件的容器，如果不指定，不启用此功能。此功能为通过粘贴来添加截屏的图片。
//		paste: document.body,
		//配置生成缩略图的选项。
		thumb:null,
		//配置压缩的图片的选项。如果此选项为false, 则图片在上传前不进行压缩。
		compress:null,
		//设置为 true 后，不需要手动调用上传，有文件选择即开始上传
//		auto:false,
		swf: '/grm/ecp/webcore/plugins/webuploader/Uploader.swf',
		//是否要分片处理大文件上传。
		chunked: true,
		//如果要分片，分多大一片？ 默认大小为5M(5242880).
//		chunkSize:5242880,
		//如果某个分片由于网络问题出错，允许自动重传多少次？默认两次
//		chunkRetry:2,
		//上传并发数。允许同时最大上传进程数。默认3
//		threads:3,
		//设置文件上传域的name。
//		fileVal:'file',
		//文件上传方式，POST或者GET。
		method:'POST',
		//指定运行时启动顺序。默认会想尝试 html5 是否支持，如果支持则使用 html5, 否则则使用 flash.可以将此值设置成 flash，来强制使用 flash 运行时。
//		runtimeOrder: 'flash',
		//是否允许在文件传输时提前把下一个文件准备好。 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。 如果能提前在当前文件传输期处理，可以节省总体耗时。
		prepareNextFile:false,
		//是否已二进制的流的方式发送文件，这样整个上传内容php://input都为文件内容， 其他参数在$_GET数组中。
		sendAsBinary: false,
		server: '/grm/ecp/webcore/FileAccessServlet?beanId=com.ygsoft.ecp.web.service.context.IFileAccessContext&method=saveFile&operParams=[]&_token=' + $.cookie("ecpDataContext.tokenId") + "&tParam=" + new Date().getTime(),
		//去重， 根据文件名字、文件大小和最后修改时间来生成hash Key
		duplicate:undefined,
		//验证文件总数量, 超出则不允许加入队列。
		fileNumLimit: 300,
		//验证文件总大小是否超出限制, 超出则不允许加入队列。
		fileSizeLimit: 0,    // 50 M
		//验证单个文件大小是否超出限制, 超出则不允许加入队列。
		fileSingleSizeLimit: 20 * 1024 * 1024    // 20 M
	};
	var serialNo = new Date().getTime();
	var uploadPanelHtml='<div id="container_w_u">'+
				            '<div id="uploader'+serialNo+'">'+
				                '<div class="queueList">'+
				                    '<div id="dndArea'+serialNo+'" class="placeholder">'+
				                        '<div id="filePicker'+serialNo+'">点击选择文件</div>'+
				                        '<p>或将照片拖到这里，单次最多可选300张</p>'+
				                    '</div>'+
				                '</div>'+
				                '<div class="statusBar" style="display:none;">'+
				                    '<div class="progress_w_u">'+
				                        '<span class="text">0%</span>'+
				                        '<span class="percentage"></span>'+
				                    '</div><div class="info"></div>'+
				                    '<div class="btns">'+
				                        '<div id="filePicker2'+serialNo+'">继续添加</div><div class="uploadBtn">开始上传</div>'+
				                    '</div>'+
				                '</div>'+
				            '</div>'+
				        '</div>';
	/**
	 * 声明numberBox对象
	 */
	var Webuploader = function(control,options){
		if(!control || control.length === 0){return;}
		this.init(control,options);
		this.render();
	}
	
	/**
	 * 通过原型定义相关方法，比如渲染、赋值等等.
	 */
	Webuploader.prototype = {
		init: function(control,options){
			this.control = control;
			this.option = $.extend(true, defaultOptions, options);
			var cId = control.attr("id");
			if(!cId){
				cId = Math.uuid();
				control.attr("id",cId);
			}
			this.option.pick.id = "#" + cId;
			var contianer = options.contianer;
			if(!contianer || contianer.length === 0){
				contianer = $("body");
			}
			this.contianer = contianer;
		},
		/**
		 * 渲染
		 */
		render: function(){
			var opt = this.option;
			//显示上传面板
			if(opt.showPanel){
				this.uploadPanel();
			}else{
				// 实例化
				var uploader = new $webUploader.Uploader(opt);
//				var uploader = $webUploader.create(opt);
				this.control[0].uploader = this.uploader = uploader;
				this.bindEvent();
			}
			
		},
		
		/**
		 * 文件上传
		 */
		bindEvent: function() {
			var uploader = this.uploader;
		    // 文件上传成功。
		    uploader.on( 'uploadSuccess', function( file ) {
		    	
		    });
		    //文件上传之前
		    uploader.on( 'beforeFileQueued', function( file ) {
		    	
		    });
		    // 文件上传失败，现实上传出错。
		    uploader.on( 'uploadError', function( file ) {
		    	
		    });
		    // 当有文件添加进来的时候
		    uploader.on( 'fileQueued', function( file ) {
		    	
		    });
		},
		
		/**
		 * 显示上传面板，可以新增、删除、旋转文件、多选文件等功能
		 */
		uploadPanel: function(){
			var contianer = this.contianer;
			contianer.append(uploadPanelHtml);
			var $wrap = $('#uploader'+serialNo),
	            // 图片容器
	            $queue = $( '<ul class="filelist"></ul>' ).appendTo( $wrap.find( '.queueList' ) ),
	            // 状态栏，包括进度和控制按钮
	            $statusBar = $wrap.find( '.statusBar' ),
	            // 文件总体选择信息。
	            $info = $statusBar.find( '.info' ),
	            // 上传按钮
	            $upload = $wrap.find( '.uploadBtn' ),
	            // 没选择文件之前的内容。
	            $placeHolder = $wrap.find( '.placeholder' ),
	            $progress = $statusBar.find( '.progress_w_u' ).hide(),
	            // 添加的文件数量
	            fileCount = 0,
	            // 添加的文件总大小
	            fileSize = 0,
	            // 优化retina, 在retina下这个值是2
	            ratio = window.devicePixelRatio || 1,
	            // 缩略图大小
	            thumbnailWidth = 110 * ratio,
	            thumbnailHeight = 110 * ratio,
	            // 可能有pedding, ready, uploading, confirm, done.
	            state = 'pedding',
	            // 所有文件的进度信息，key为file id
	            percentages = {},
	            // WebUploader实例
	            uploader,
	            opt = this.option;
			
			if(opt.pick){
				opt.pick.id = '#filePicker'+serialNo;
			}else{
				opt.pick = {
					id: '#filePicker'+serialNo,
				    innerHTML: "添加附件...",
				    multiple:true 
				};
			}
			opt.dnd = '#dndArea'+serialNo;
			opt.paste = '#uploader'+serialNo;
			opt.server = '/ecp/webcore/plugins/webuploader/server/fileupload.php';
	        // 实例化
	        uploader = new $webUploader.Uploader(opt);
	        // 添加“添加文件”的按钮，
	        uploader.addButton({
				id:'#filePicker2'+serialNo,
				innerHTML:"继续添加"
			});
	        setTimeout(function(){
	        	$($("#filePicker2"+serialNo).children()[1]).css({"height":"44px","width":"60px","left": "10px"});
	        },0)
	        // 当有文件添加进来时执行，负责view的创建
	        function addFile( file ) {
	            var $li = $( '<li id="' + file.id + '">' +
	                    '<p class="title">' + file.name + '</p>' +
	                    '<p class="imgWrap"></p>'+
	                    '<p class="progress_w_u"><span></span></p>' +
	                    '</li>' ),

	                $btns = $('<div class="file-panel">' +
	                    '<span class="cancel">删除</span>' +
	                    '<span class="rotateRight">向右旋转</span>' +
	                    '<span class="rotateLeft">向左旋转</span></div>').appendTo( $li ),
	                $prgress = $li.find('p.progress_w_u span'),
	                $wrap = $li.find( 'p.imgWrap' ),
	                $info = $('<p class="error"></p>'),

	                showError = function( code ) {
	                    switch( code ) {
	                        case 'exceed_size':
	                            text = '文件大小超出';
	                            break;

	                        default:
	                            text = '上传失败，请重试';
	                            break;
	                    }

	                    $info.text( text ).appendTo( $li );
	                };

	            if ( file.getStatus() === 'invalid' ) {
	                showError( file.statusText );
	            } else {
	                // @todo lazyload
	                $wrap.text( '预览中' );
	                uploader.makeThumb( file, function( error, src ) {
	                    if ( error ) {
	                        $wrap.text( '不能预览' );
	                        return;
	                    }

	                    var img = $('<img src="'+src+'">');
	                    $wrap.empty().append( img );
	                }, thumbnailWidth, thumbnailHeight );

	                percentages[ file.id ] = [ file.size, 0 ];
	                file.ratation = 0;
	            }

	            file.on('statuschange', function( cur, prev ) {
	                if ( prev === 'progress_w_u' ) {
	                    $prgress.hide().width(0);
	                } else if ( prev === 'queued' ) {
	                    $li.off( 'mouseenter mouseleave' );
	                    $btns.remove();
	                }

	                // 成功
	                if ( cur === 'error' || cur === 'invalid' ) {
	                    showError( file.statusText );
	                    percentages[ file.id ][ 1 ] = 1;
	                } else if ( cur === 'queued' ) {
	                    percentages[ file.id ][ 1 ] = 0;
	                } else if ( cur === 'progress_w_u' ) {
	                    $info.remove();
	                    $prgress.css('display', 'block');
	                }

	                $li.removeClass( 'state-' + prev ).addClass( 'state-' + cur );
	            });

	            $li.on( 'mouseenter', function() {
	                $btns.stop().animate({height: 30});
	            });

	            $li.on( 'mouseleave', function() {
	                $btns.stop().animate({height: 0});
	            });

	            $btns.on( 'click', 'span', function() {
	                var index = $(this).index(),
	                    deg;

	                switch ( index ) {
	                    case 0:
	                        uploader.removeFile( file );
	                        return;

	                    case 1:
	                        file.ratation += 90;
	                        break;

	                    case 2:
	                        file.ratation -= 90;
	                        break;
	                }

	                // -webkit-transform: rotate(90deg);
	                index && (deg = 'rotate(' + file.ratation + 'deg)', $wrap.css({
	                    '-webkit-transform': deg,
	                    '-mos-transform': deg,
	                    '-o-transform': deg,
	                    'transform': deg
	                }));
	            });

	            $li.appendTo( $queue );
	        }

	        // 负责view的销毁
	        function removeFile( file ) {
	            var $li = $('#'+file.id);

	            delete percentages[ file.id ];
	            updateTotalProgress();
	            $li.off().find('.file-panel').off().end().remove();
	        }

	        function updateTotalProgress() {
	            var loaded = 0,
	                total = 0,
	                spans = $progress.children(),
	                percent;

	            $.each( percentages, function( k, v ) {
	                total += v[ 0 ];
	                loaded += v[ 0 ] * v[ 1 ];
	            } );

	            percent = total ? loaded / total : 0;

	            spans.eq( 0 ).text( Math.round( percent * 100 ) + '%' );
	            spans.eq( 1 ).css( 'width', Math.round( percent * 100 ) + '%' );
	            updateStatus();
	        }

	        function updateStatus() {
	            var text = '', stats;

	            if ( state === 'ready' ) {
	                text = '选中' + fileCount + '张图片，共' +
	                	$webUploader.formatSize( fileSize ) + '。';
	            } else if ( state === 'confirm' ) {
	                stats = uploader.getStats();
	                if ( stats.uploadFailNum ) {
	                    text = '已成功上传' + stats.successNum+ '张照片至XX相册，'+
	                        stats.uploadFailNum + '张照片上传失败，<a class="retry" href="#">重新上传</a>失败图片或<a class="ignore" href="#">忽略</a>'
	                }

	            } else {
	                stats = uploader.getStats();
	                text = '共' + fileCount + '张（' +
	                	$webUploader.formatSize( fileSize )  +
	                        '），已上传' + stats.successNum + '张';

	                if ( stats.uploadFailNum ) {
	                    text += '，失败' + stats.uploadFailNum + '张';
	                }
	            }

	            $info.html( text );
	        }

	        function setState( val ) {
	            var file, stats;

	            if ( val === state ) {
	                return;
	            }

	            $upload.removeClass( 'state-' + state );
	            $upload.addClass( 'state-' + val );
	            state = val;

	            switch ( state ) {
	                case 'pedding':
	                    $placeHolder.show();
	                    $queue.hide();
	                    $statusBar.hide();
	                    break;

	                case 'ready':
	                    $placeHolder.hide();
	                    $( '#filePicker2'+serialNo ).show();
	                    $queue.show();
	                    $statusBar.show();
	                    break;

	                case 'uploading':
	                    $( '#filePicker2'+serialNo ).hide();
	                    $progress.show();
	                    $upload.text( '暂停上传' );
	                    break;

	                case 'paused':
	                    $progress.show();
	                    $upload.text( '继续上传' );
	                    break;

	                case 'confirm':
	                    $progress.hide();
	                    $upload.text( '开始上传' ).addClass( 'disabled' );

	                    stats = uploader.getStats();
	                    if ( stats.successNum && !stats.uploadFailNum ) {
	                        setState( 'finish' );
	                        return;
	                    }
	                    break;
	                case 'finish':
	                    stats = uploader.getStats();
	                    if ( stats.successNum ) {
	                        utils.notify( '上传成功' );
	                    } else {
	                        // 没有成功的图片，重设
	                        state = 'done';
	                        location.reload();
	                    }
	                    break;
	            }

	            updateStatus();
	        }

	        uploader.onUploadBeforeSend = function( file, data ) {
	            data.md5 = file.md5 || '';
	        };

	        uploader.onUploadProgress = function( file, percentage ) {
	            var $li = $('#'+file.id),
	                $percent = $li.find('.progress_w_u span');

	            $percent.css( 'width', percentage * 100 + '%' );
	            percentages[ file.id ][ 1 ] = percentage;
	            updateTotalProgress();
	        };

	        uploader.onFileQueued = function( file ) {
	            var start = Date.now();

	            fileCount++;
	            fileSize += file.size;

	            if ( fileCount === 1 ) {
	                $placeHolder.hide();
	                $statusBar.show();
	            }

	           // Md5File( file, function( value ) {
	            //    var $li = $('#'+file.id);
	            //    file.md5 = value;

	            //    $li.append( '<p class="log">md5:' + ((Date.now() - start)/1000).toFixed(2) + '秒</p>')
	           // });

	            addFile( file );
	            setState( 'ready' );
	            updateTotalProgress();
	        };

	        uploader.onFileDequeued = function( file ) {
	            fileCount--;
	            fileSize -= file.size;

	            if ( !fileCount ) {
	                setState( 'pedding' );
	            }

	            removeFile( file );
	            updateTotalProgress();

	        };

	        uploader.on( 'all', function( type ) {
	            var stats;
	            switch( type ) {
	                case 'uploadFinished':
	                    setState( 'confirm' );
	                    break;

	                case 'startUpload':
	                    setState( 'uploading' );
	                    break;

	                case 'stopUpload':
	                    setState( 'paused' );
	                    break;

	            }
	        });

	        uploader.onError = function( code ) {
	            utils.notify( 'Eroor: ' + code );
	        };

	        uploader.onUploadChunkcontinue = function( file, ret ) {
	            if ( ret.exist ) {
	                var $li = $( '#'+file.id );
	                $li.append( '<p class="log">跳过' + $webUploader.formatSize( file.size - file.loaded ) + '</p>' );
	                return false;
	            }
	        };

	        $upload.on('click', function() {
	            if ( $(this).hasClass( 'disabled' ) ) {
	                return false;
	            }

	            if ( state === 'ready' ) {
	                uploader.upload();
	            } else if ( state === 'paused' ) {
	                uploader.upload();
	            } else if ( state === 'uploading' ) {
	                uploader.stop();
	            }
	        });

	        $info.on( 'click', '.retry', function() {
	            uploader.retry();
	        } );

	        $info.on( 'click', '.ignore', function() {
	            utils.notify( 'todo' );
	        } );

	        $upload.addClass( 'state-' + state );
	        updateTotalProgress();

	        var Md5File = (function(){
	            return function( file, cb ) {
	                var worker = new Worker( 'md5File.js' );
	                worker.onmessage = function( e ) {
	                    cb( e.data, file );
	                    worker.terminate();
	                };

	                worker.postMessage( file.source );
	            }
	        })();
		}
	};
	(function($) {
		var old = $.fn.webuploader;
		$.fn.webuploader = function(options){
			var me = this;
			options = options || {};
			var value;
			//如果第一个参数传入的是对象或空则初始化空件，如果传入的是字符串，则认为是调用里面的内部方法。
			if (typeof(options) === "object") {
				this.each(function() {
					var instanceOptions = $.extend({}, options, true);
					var instance = new Webuploader($(this), instanceOptions);
				});
				return this[0].uploader;
			} 
		};
		$.fn.webuploader.Constructor = Webuploader;
		$.fn.webuploader.noConflict = function() {
			$.fn.webuploader = old;
			return this;
		};
	}(jQuery));
	return Webuploader.prototype;
		
});